package com.isesol.arch.web.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

/**
 * 
 * 框架上下文监听类.
 * <p>描述:负责初始化上下文环境</p>
 * @author <a href="mailto:admin@ddatsh.com">Peter Zhang(章培德)</a>
 */
public class ArchListener implements ServletContextListener {

	private Logger LOGGER = LoggerFactory.getLogger(getClass());

	/** Spring框架上下文. */
	private static ApplicationContext ctx = null;
	private static final List<ServletContextListener> listeners = new ArrayList<ServletContextListener>();
	/** 系统根目录. */
	private static String rootPath;
	
	/**
	 * 获取系统根目录.
	 */
	public static String getRootPath() {
		return rootPath;
	}
	
	/**
	 * 从Spring中获取Bean.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(Class<T> beanClass) {
		String[] beanNames = ctx.getBeanNamesForType(beanClass);
		
		if (beanNames != null && beanNames.length > 0) {
			String className = beanClass.getSimpleName();
			
			for (String beanName : beanNames) {
				if (className.equalsIgnoreCase(beanName)) {
					return (T)getBean(beanName);
				}
			}
			
			return (T)getBean(beanNames[beanNames.length-1]);
		}
		
		return null;
	}
	
	/**
	 * 从Spring中获取Bean.
	 */
	public static Object getBean(String beanName) {
		return ctx.getBean(beanName);
	}
	
	/**
	 * 从Spring中获取Bean.
	 * @return 如果存在则返回对应的Bean；如果不存在则返回null
	 */
	public static Object getBeanNotRequired(String beanName) {
		if (ctx != null && ctx.containsBean(beanName)) {
			return getBean(beanName);
		}
		
		return null;
	}
	
	/**
	 * 添加监听器.
	 * @param listener 要添加的监听器
	 */
	public static void addListener(ServletContextListener listener) {
		if (!listeners.contains(listener)) {
			listeners.add(listener);
		}
	}
	
	/**
	 * 触发监听器.
	 */
	public void fireEvent(ServletContextEvent event) {
		for (ServletContextListener listener : listeners) {
			listener.contextInitialized(event);
		}
	}

	@Override
	public void contextDestroyed(ServletContextEvent event) {

		for (ServletContextListener listener : listeners) {
			listener.contextDestroyed(event);
		}
		ctx = null;
		unbindResource();

		Enumeration<Driver> drivers = DriverManager.getDrivers();
		while (drivers.hasMoreElements()) {
			Driver driver = drivers.nextElement();
			try {
				DriverManager.deregisterDriver(driver);
				LOGGER.warn("stopping... ", driver);
			} catch (SQLException e) {
				LOGGER.error("stopping driver ",driver);
			}
		}
		Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
		Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
		for(Thread t:threadArray) {
			if(t.getName().contains("Abandoned connection cleanup thread")||t.getName().contains("task_excutor")) {
				synchronized(t) {
					t.stop();
				}
			}
		}
	}

	/* (non-Javadoc)
	 * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		rootPath = event.getServletContext().getRealPath("/");
		ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(event.getServletContext());
		fireEvent(event);
	}

	private void unbindResource() {
		Map<Object, Object> resource = TransactionSynchronizationManager.getResourceMap();
		
		if (resource != null) {
			for (Object key : resource.keySet()) {
				TransactionSynchronizationManager.unbindResourceIfPossible(key);
			}
		}
	}
}
